import datetime
import logging

from pylons import config
from pylons.i18n import _
from couchdb import Server, client
from couchdb.schema import *

log = logging.getLogger(__name__)

db_connect_string = config['db_connect_string']
db_name = config['db_name']

db = Server(db_connect_string)[db_name]

# Define relational mapping schema for object types

class User(Document):
    '''User object map; users who are able to authenticate to the app'''
    
    type = TextField(default='user')
    username = TextField()
    fullname = TextField()
    email = TextField()
    password = TextField()
    password_salt = TextField()
    timezone = TextField(default=config['timezone'])
    language = TextField(default=config['lang'])
    theme = TextField(default=config['theme'])
    roles = ListField(
        TextField()
    )
    enabled = BooleanField(default=True)

class Role(Document):
    '''Role object map; roles that will have users and privileges assigned'''
    
    type = TextField(default='role')
    name = TextField()
    protected = BooleanField(default=False)

class TicketDefinition(Document):
    '''TicketDefinition object map; defines different ticket types which can be
    submitted, also keeping all older versions of the schema to facilitate
    display of tickets created against a certain version.'''
    
    type = TextField(default='ticket_definition')
    name = TextField()
    taggable_name = TextField()
    enabled = BooleanField(default=True)
    versions = ListField(
        DictField(Schema.build(
            fields = ListField(
                DictField(Schema.build(
                    anchor_x = IntegerField(),
                    anchor_y = IntegerField(),
                    length_x = IntegerField(),
                    length_y = IntegerField(),
                    default_value = TextField(),
                    type = TextField(),
                    required = BooleanField(),
                    name = TextField(),
                    description = TextField()
                ))
            ),
            created_by = TextField(),
            created_timestamp = DateTimeField(),
            default_assignee = TextField(),
            approvers = ListField(
                TextField()
            ),
            simultaneous_approvals = BooleanField(),
            on_modify = DictField(Schema.build(
                keep_assignee = BooleanField(),
                keep_approvals = BooleanField()
            )),
            on_reopen = DictField(Schema.build(
                keep_assignee = BooleanField(),
                keep_approvals = BooleanField()
            )),
            privileges = DictField(Schema.build(
                create = ListField(
                    TextField()
                ),
                view = ListField(
                    TextField()
                ),
                view_technical_notes = ListField(
                    TextField()
                ),
                assign = ListField(
                    TextField()
                ),
                assign_to = ListField(
                    TextField()
                ),
                reassign = ListField(
                    TextField()
                ),
                add_notes = ListField(
                    TextField()
                ),
                add_technical_notes = ListField(
                    TextField()
                ),
                modify_fields = ListField(
                    TextField()
                ),
                delete_notes = ListField(
                    TextField()
                ),
                delete_technical_notes = ListField(
                    TextField()
                ),
                delete = ListField(
                    TextField()
                )
            ))
        ))
    )

class Ticket(Document):
    '''Ticket object map; represents individual tickets'''
    
    type = TextField(default='ticket')
    form_id = TextField()
    form_version = IntegerField()
    form_data = ListField( # each version is appended to this list
        ListField( # values for form fields stored in this list
            TextField()
        ),
    )
    tags = ListField(
        TextField()
    )
    friendly_id = TextField()
    status = TextField()
    created_timestamp = DateTimeField()
    modified_timestamp = DateTimeField()
    completed_timestamp = DateTimeField()
    actions = ListField(
        DictField(Schema.build(
            type = TextField(),
            timestamp = DateTimeField(),
            user = TextField(),
            notes = TextField(),
            technical_notes = TextField()
        ))
    )
    approvals_pending = ListField(
        TextField()
    )
    assignee = TextField()


# Create _design documents, complete any needed database upgrades

if not 'pedetra_db_info' in db:
    log.warn(_('Empty database found; populating design documents'))
    db['pedetra_db_info'] = {
        'version': 0
    }

db_info = db['pedetra_db_info']

if db_info['version'] < 1:
    upgrade_ver = 1
    log.warn(_('Upgrading database from version %d to version %d') % (db_info['version'], upgrade_ver))
    
    # Create design documents
    db['_design/user'] = {
        'views': {
            'by_username': {
                'map': "function(doc) { if(doc.type == 'user') emit(doc.username, doc); }"
            }
        }
    }
    db['_design/role'] = {
        'views': {
            'by_name': {
                'map': "function(doc) { if(doc.type == 'role') emit(doc.name, doc); }"
            }
        }
    }
    db['_design/ticket_definition'] = {
        'views': {
            
        }
    }
    db['_design/ticket'] = {
        'views': {
            'by_friendly_id': {
                'map': "function(doc) { emit(doc.friendly_id, doc); }"
            }
        }
    }
    
    # Create protected roles
    user_admin_role = Role()
    user_admin_role.protected = True
    user_admin_role.name = _("User Administrator")
    user_admin_role.store(db)
    db_info['user_admin_role_id'] = user_admin_role['_id']
    
    definition_admin_role = Role()
    definition_admin_role.protected = True
    definition_admin_role.name = _("Ticket Definition Administrator")
    definition_admin_role.store(db)
    db_info['definition_admin_role_id'] = definition_admin_role['_id']
    
    log.warn(_('Database upgrade from version %d to version %d completed') % (db_info['version'], upgrade_ver))
    db_info['version'] = 1
    db['pedetra_db_info'] = db_info

